#pragma once 

#include "CDXTexture2D.h"
#include "CDX3DTransform.h"
#include "CDXEffect.h"
#include "CDXMesh.h"

#ifndef __SWIG__
#include <vector>
#endif

#ifdef __SWIG__
#include "mui_typemap.i"
%include <typemaps.i>

%apply SWIGTYPE* OUTPUT {D3D11_DEPTH_STENCIL_DESC* ppStateDesc}; //GetDepthState
%apply SWIGTYPE** OUTPUT {CDXTexture2D** ppFrameBuffer};
%apply SWIGTYPE** OUTPUT {CDXTexture2D** ppDepthBuffer};
%apply SWIGTYPE* OUTPUT {D3D11_VIEWPORT* outviewport};
%apply SWIGTYPE** OUTPUT {ID2D1Mesh **mesh};
%apply SWIGTYPE* OUTPUT {D2D1_ANTIALIAS_MODE* pOutAntialiasMode};
%apply SWIGTYPE* OUTPUT {D2D1_TEXT_ANTIALIAS_MODE* pOutTextAntialiasMode};
%apply SWIGTYPE** OUTPUT {ID3DX11Effect** pOutEffect};

#endif

enum StretchType
{
	Fill = 0,
	Uniform = 1,
	UniformFill = 2, 
	NoStretch = 3
};
class CDXRenderer : public CDXBase, public CDX3DTransform, public CRefCount, public CDXRenderResourceLocker
{
protected:
	
	struct FxElem
	{
		CDXEffect* pEffect;
		UINT techIdx;
		UINT passIdx;
		FxElem() : pEffect(NULL), techIdx(0), passIdx(0)
		{}
		FxElem(CDXEffect* pFX, UINT tIdx, UINT pIdx) : pEffect(pFX), techIdx(tIdx), passIdx(pIdx)
		{}
		bool operator == (const FxElem& fx2);
	};
	struct ClipRectSet
	{
		D3DXVECTOR3 clipRect[4]; //lt, rt, lb, rb
		D2D1_ANTIALIAS_MODE antialiasMode;
		ClipRectSet(const D3DXVECTOR3 rect[4], D2D1_ANTIALIAS_MODE aMode)
		{
			memcpy((void*)clipRect, rect, sizeof(D3DXVECTOR3)*4);
			antialiasMode = aMode;
		}
	};
protected:
	BOOL m_bD3DDrawing;
	BOOL m_bD2DDrawing;
	BOOL m_bD2DDrawingEndByD3D;
	CDXTexture2D* m_pFrameBuffer;
	CDXTexture2D* m_pDepthBuffer;
	std::vector<CDXTexture2D*> m_pFrameBufferStack;
	std::vector<CDXTexture2D*> m_pDepthBufferStack;
	DXGI_FORMAT m_FrameBufferFmt;

	FxElem m_Fx;
	std::vector<FxElem> m_FxStack;
	
	CDXGeometry* m_pRenderGeometry;
	std::vector<CDXGeometry*> m_pRenderGeometryStack;
	
	ClipRectSet* m_pClipRect;
	std::vector<ClipRectSet*> m_clipRectStack;

	D3DXMATRIX m_matView;
	D3DXMATRIX m_matProj;
	
	CD2DColorBrushLibrary* m_pColorBrushLibrary;
	CDXEffectLibrary* m_pEffectLibrary;
	CDXMeshLibrary* m_pMeshLibrary;

protected:
	std::vector<CDXTexture2D*> m_pDefaultDepthBuffer; //only different in size.
	virtual HRESULT _GetDefaultDepthBuffer(UINT width, UINT height, CDXTexture2D** ppDepthBuffer);
	std::vector<ID3D11DepthStencilState*> m_pDepthStencilStateCache;
	virtual HRESULT _CreateDepthStencilState(D3D11_DEPTH_STENCIL_DESC* pDesc, ID3D11DepthStencilState** ppState);
	
	virtual HRESULT _Init();
	virtual HRESULT _initColorBrushLibrary();
	virtual HRESULT _initEffectLibrary();
	virtual HRESULT _initMeshLibrary();
	virtual HRESULT _updateBordMesh(const D2D1_RECT_F& rect, const float bordW[4], UINT texW, UINT texH);
	virtual HRESULT _InitDepthState();
	virtual BOOL _IsValidFrameBuffer(CDXTexture2D* pFrameBuf);
	virtual BOOL _IsValidDepthBuffer(CDXTexture2D* pDepthBuf);
	virtual HRESULT _CalcStretchTypeSrcRect(StretchType sType, const D2D1_RECT_F& inDstRect, float srcW, float srcH, D2D1_RECT_F& outDstRect, D2D1_RECT_F& outSrcRect);

	virtual HRESULT BindFrameBuffersToDevice();
	virtual HRESULT UnbindFrameBufferFromDevice();

	HRESULT CDXRenderer::BindInputLayout();
	virtual HRESULT BindRenderGeometryToDevice();
	virtual HRESULT BindEffectToDevice();
	virtual HRESULT UnBindEffectFromDevice();
	virtual HRESULT BindMatrixToStdVs();

	virtual HRESULT BindD2DTransform();	
	virtual HRESULT UnbindD2DTransform();

	virtual HRESULT BindD2DClipRect();
	virtual HRESULT UnbindD2DClipRect();

public:
	CDXRenderer(CDXDevice* pDevice);
	virtual ~CDXRenderer();
	///////Some Convenient functions////////////////
	virtual HRESULT UpdateCamViewByViewport();
	virtual HRESULT UpdateViewportByFrameBuf();
	///////////Set Render Target///////////
	virtual HRESULT SetDepthStencilState(D3D11_DEPTH_STENCIL_DESC* pStateDesc);
	virtual HRESULT GetDepthStencilState(D3D11_DEPTH_STENCIL_DESC* ppStateDesc);// need to be release 
	virtual HRESULT SetFrameBuffer(CDXTexture2D* pFrameBuffer, BOOL bUpdateViewport = TRUE, BOOL bUpdateCamView = TRUE);
	virtual HRESULT SetFrameBuffer(CDXTexture2D* pFrameBuffer, CDXTexture2D* pDepthBuffer, BOOL bUpdateViewport = TRUE, BOOL bUpdateCamView = TRUE);
	virtual HRESULT GetFrameBuffer(CDXTexture2D** ppFrameBuffer, CDXTexture2D** ppDepthBuffer);
	
	virtual HRESULT PushFrameBuffer(CDXTexture2D* pFrameBuffer, BOOL bUpdateViewport = TRUE, BOOL bUpdateCamView = TRUE);
	virtual HRESULT PushFrameBuffer(CDXTexture2D* pFrameBuffer, CDXTexture2D* pDepthBuffer, BOOL bUpdateViewport = TRUE, BOOL bUpdateCamView = TRUE);
	virtual HRESULT PopFrameBuffer(BOOL bUpdateViewport, BOOL bUpdateCamView = TRUE);

	virtual HRESULT SetFrameBufferFormat(DXGI_FORMAT fmt);
	virtual DXGI_FORMAT GetFrameBufferFormat();
	//////////For Effect Setting//////////
	virtual HRESULT SetEffect(ID3DX11Effect* pDXEffect, UINT techidx = 0, UINT passIdx = 0);
	virtual HRESULT SetEffect(CDXEffect* pEffect, UINT techidx = 0, UINT passIdx = 0);

	virtual HRESULT GetEffect(ID3DX11Effect** pOutEffect);

	virtual HRESULT PushEffect();
	virtual HRESULT PopEffect();

	//////////3d render setting///////
	virtual HRESULT SetViewPort(const D3D11_VIEWPORT* viewport, BOOL bUpdateProjMat);
	virtual HRESULT GetViewPort(D3D11_VIEWPORT* outViewport);
	virtual HRESULT SetViewMatrix(const D3DXMATRIX* matView);
	virtual D3DXMATRIX GetViewMatrix();
	virtual HRESULT SetProjectMatrix(const D3DXMATRIX* matProj);
	virtual D3DXMATRIX GetProjectMatrix();

	virtual HRESULT SetRenderGeometry(CDXGeometry* pGeometry);  
	virtual HRESULT PushRenderGeometry();
	virtual HRESULT PopRenderGeometry();

	virtual HRESULT BindResourcesToDevice();
	


	/////////Create Structure
	virtual HRESULT CreateD2DMesh(ID2D1Mesh **mesh);
	
	/////////3D Render Command///////////////
	virtual HRESULT BeginDrawD3D();
	virtual HRESULT EndDrawD3D();
	virtual HRESULT ClearColorD3D(FLOAT color[4]);
	virtual HRESULT ClearDepthD3D();
	virtual HRESULT DrawD3D(BOOL bStdVS);
	virtual HRESULT DrawColorRectangleD3D(D2D1_RECT_F rect, FLOAT color[4]); 
	virtual HRESULT DrawTexturedRectangleD3D(D2D1_RECT_F rect, CDXTexture2D* pTexture, FLOAT color[4], StretchType stretchType = Fill); 
	virtual HRESULT DrawRectangleD3D(D2D1_RECT_F rect, CDXEffect* pEffect, UINT techIdx, UINT passIdx); 
	virtual HRESULT DrawBorderRectangleD3D(D2D1_RECT_F rect, const float bordW[4], CDXTexture2D* pTexture, FLOAT color[4]);
	virtual HRESULT DrawBorderRectangleD3D(D2D1_RECT_F rect, const float bordW[4], UINT texW, UINT texH, CDXEffect* pEffect, UINT techIdx, UINT passIdx); 
	
	////////2D Render Command
	virtual HRESULT BeginDraw();
	virtual HRESULT EndDraw();
	/////////2D Render Command///////////////
	virtual HRESULT ClearColor(FLOAT color[4]);
	virtual HRESULT DrawBitmapSubRegion(CDXTexture2D* pTexture, D2D1_RECT_F destinationRectangle, D2D1_RECT_F sourceRectangle,
		FLOAT opacity = 1.0, D2D1_BITMAP_INTERPOLATION_MODE interpolationMode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR );

	virtual HRESULT DrawBitmap(CDXTexture2D* pTexture, D2D1_RECT_F destinationRectangle, StretchType stretchType = Uniform,
		FLOAT opacity = 1.0, D2D1_BITMAP_INTERPOLATION_MODE interpolationMode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
	
	virtual HRESULT DrawBitmapEx(ID2D1Bitmap* pBitmap, D2D1_RECT_F destinationRectangle,
		FLOAT opacity = 1.0, D2D1_BITMAP_INTERPOLATION_MODE interpolationMode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, const D2D1_RECT_F* sourceRectangle = NULL);
	
	virtual HRESULT DrawBorderBitmap(CDXTexture2D* pTexture, const float bordW[4], D2D1_RECT_F destinationRectangle,
		FLOAT opacity = 1.0, D2D1_BITMAP_INTERPOLATION_MODE interpolationMode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, const D2D1_RECT_F* sourceRectangle = NULL);

	virtual HRESULT DrawEllipse( const D2D1_ELLIPSE &ellipse, ID2D1Brush* brush, FLOAT strokeWidth = 1.0f);
	virtual HRESULT DrawTexturedEllipse( const D2D1_ELLIPSE &ellipse, CDXTexture2D* brush, FLOAT strokeWidth = 1.0f);
	virtual HRESULT DrawColorEllipse( const D2D1_ELLIPSE &ellipse, FLOAT color[4], FLOAT strokeWidth = 1.0f);
	virtual HRESULT DrawGeometry( ID2D1Geometry *geometry, ID2D1Brush *brush, FLOAT strokeWidth = 1.0f,
		ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawColorGeometry( ID2D1Geometry *geometry, FLOAT color[4], FLOAT strokeWidth = 1.0f,
		ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawTexturedGeometry( ID2D1Geometry *geometry, CDXTexture2D* pBrush, FLOAT strokeWidth = 1.0f,
		ID2D1StrokeStyle *strokeStyle = NULL);


	virtual HRESULT DrawLine(D2D1_POINT_2F point0, D2D1_POINT_2F point1, ID2D1Brush *brush,	FLOAT strokeWidth = 1.0f,
		ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawTexturedLine(D2D1_POINT_2F point0, D2D1_POINT_2F point1, CDXTexture2D *brush, FLOAT strokeWidth = 1.0f,
		ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawColorLine(D2D1_POINT_2F point0, D2D1_POINT_2F point1, FLOAT color[4], FLOAT strokeWidth = 1.0f,
		ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawRectangle(D2D1_RECT_F  rect, ID2D1Brush *brush, FLOAT strokeWidth = 1.0f, ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawTexturedRectangle(D2D1_RECT_F  rect, CDXTexture2D* brush, FLOAT strokeWidth = 1.0f, ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawColorRectangle(D2D1_RECT_F  rect, FLOAT color[4], FLOAT strokeWidth = 1.0f, ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawRoundedRectangle(const D2D1_ROUNDED_RECT &roundedRect, ID2D1Brush *brush, FLOAT strokeWidth = 1.0f, ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawTexturedRoundedRectangle(const D2D1_ROUNDED_RECT &roundedRect, CDXTexture2D *pBrush, FLOAT strokeWidth = 1.0f, ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawColorRoundedRectangle(const D2D1_ROUNDED_RECT &roundedRect, FLOAT color[4], FLOAT strokeWidth = 1.0f, ID2D1StrokeStyle *strokeStyle = NULL);
	virtual HRESULT DrawText(WCHAR *string, UINT stringLength,  IDWriteTextFormat *textFormat, D2D1_RECT_F layoutRect,
		ID2D1Brush *defaultForegroundBrush, D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE, DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL);
	virtual HRESULT DrawColorText(WCHAR *string, UINT stringLength,  IDWriteTextFormat *textFormat, D2D1_RECT_F layoutRect,
		FLOAT color[4], D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE, DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL);
	virtual HRESULT DrawTexturedText(WCHAR *string, UINT stringLength,  IDWriteTextFormat *textFormat, D2D1_RECT_F layoutRect,
		CDXTexture2D *pBrush, D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE, DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL);
	virtual HRESULT DrawTextLayout(D2D1_POINT_2F origin, IDWriteTextLayout *textLayout, ID2D1Brush *defaultForegroundBrush, D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE);
	virtual HRESULT DrawColorTextLayout(D2D1_POINT_2F origin, IDWriteTextLayout *textLayout, FLOAT color[4], D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE);
	virtual HRESULT DrawTexturedTextLayout(D2D1_POINT_2F origin, IDWriteTextLayout *textLayout, CDXTexture2D* pBrush, D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE);
	virtual HRESULT FillEllipse(const D2D1_ELLIPSE &ellipse, ID2D1Brush *brush);
	virtual HRESULT FillTexturedEllipse(const D2D1_ELLIPSE &ellipse, CDXTexture2D *brush);
	virtual HRESULT FillColorEllipse(const D2D1_ELLIPSE &ellipse, FLOAT color[4]);
	virtual HRESULT FillGeometry(ID2D1Geometry *geometry, ID2D1Brush *brush, ID2D1Brush *opacityBrush = NULL);
	virtual HRESULT FillOpacityMask( ID2D1Bitmap *opacityMask, ID2D1Brush *brush, D2D1_OPACITY_MASK_CONTENT content,
		D2D1_RECT_F destinationRectangle, D2D1_RECT_F sourceRectangle);
	virtual HRESULT FillTexturedOpacityMask( CDXTexture2D *opacityMask, CDXTexture2D *brush, D2D1_OPACITY_MASK_CONTENT content,
		D2D1_RECT_F destinationRectangle, D2D1_RECT_F sourceRectangle);

	virtual HRESULT FillRectangle( D2D1_RECT_F rect, ID2D1Brush *brush);
	virtual HRESULT FillColorRectangle( D2D1_RECT_F rect, float color[4]);
	virtual HRESULT FillTexturedRectangle( D2D1_RECT_F rect, CDXTexture2D* brush);

	virtual HRESULT FillRoundedRectangle(const D2D1_ROUNDED_RECT &roundedRect, ID2D1Brush *brush);
	virtual HRESULT FillTexturedRoundedRectangle(const D2D1_ROUNDED_RECT &roundedRect, CDXTexture2D *brush);
	virtual HRESULT FillColorRoundedRectangle(const D2D1_ROUNDED_RECT &roundedRect, FLOAT color[4]);

	///2D State Setting
	virtual HRESULT SaveDrawingState(ID2D1DrawingStateBlock *drawingStateBlock);
	virtual HRESULT RestoreDrawingState(ID2D1DrawingStateBlock *drawingStateBlock);
	virtual HRESULT PushAxisAlignedClip(D2D1_RECT_F clipRect, D2D1_ANTIALIAS_MODE antialiasMode = D2D1_ANTIALIAS_MODE_ALIASED);
	virtual HRESULT PopAxisAlignedClip();
	virtual HRESULT SetAntialiasMode(D2D1_ANTIALIAS_MODE antialiasMode);
	virtual HRESULT GetAntialiasMode(D2D1_ANTIALIAS_MODE* pOutAntialiasMode);
	virtual HRESULT SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode);
	virtual HRESULT GetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE* pOutTextAntialiasMode);

};
